package com.cn.lp.converter.demo;

import com.alibaba.fastjson.JSON;
import com.cn.lp.converter.ConverterHolder;
import com.cn.lp.converter.MergeResult;
import com.cn.lp.converter.demo.converter.*;
import com.google.common.collect.Sets;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

@Service
public class InitService {

    @Resource
    private TestComponentConverter testComponentConverter;

    @PostConstruct
    public void init() {
        testBaseBeanConverter();
        testBaseMapConverter();
        testComponentConverter();
        testMapperFieldConverter();
        testMappingFieldConverter();
        testMapMethodConverter();
        testBeanMethodConverter();
        testCommonTypeChange();
    }

    /**
     * primary的运用
     * CommonTypeChange是封装了常用方法的工具接口，大家可以酌情使用，通过primary = true 就能提高优先度，保证子接口的方法被优先调用
     */
    private void testCommonTypeChange() {
        TestCommonTypeChangeConverter.EntityA entityA = new TestCommonTypeChangeConverter.EntityA();
        entityA.setChangeData1("10000");
        entityA.setChangeDate2("10086");
        TestCommonTypeChangeConverter converter = ConverterHolder.getConverter(TestCommonTypeChangeConverter.class);
        System.out.println("testBeanMethodConverter---------------- 旧对象A：" + JSON.toJSONString(entityA));
        TestCommonTypeChangeConverter.EntityB entityB = converter.convertTo(entityA);
        System.out.println("testBeanMethodConverter ---------------- 新对象B：" + JSON.toJSONString(entityB));
        System.out.println("");
    }

    /**
     * 指定方法
     * JudgeEmptyMethod - 判断参数是否为空，返回值为boolean，匹配规则：入参类型和Source的类型
     * DefaultValueMethod - 默认值，如果参数为空，则修改为默认值，匹配规则：返回的类型和Source参数的类型
     * TypeChangeMethod - 类型转换，比如int -> String， 匹配规则：参数1的类型和Source参数类型，返回类型和target参数类型
     * judgeSame - 判断是否相同，如果相同则跳过字段，匹配规则： 参数1的类型和Source参数类型，参数2的类型和target参数类型
     * postMergeTo - ConvertTo 之后触发， 能改变最终返回的Entity
     * postConvertTo - MergeTo 之后触发， 能改变最终返回的Entity
     *
     * 参数说明:
     * fieldNameFilter - 字段过滤（name，注释，正则）指定字段生效或者不生效
     * primary - 多个规则生效的情况下，提高优先度， 默认前面的方法优先度更高（不能完全保证），所以primary最好只有一个
     *
     * 特殊规则 ：
     * 1. 由于这里没有fromMap方法，assignFromMap保持为false, 如果设为true则导致该方法不生效
     *
     * 2. ConverterMapper中的defaultValue如果为false，则DefaultValueMethod不生效
     *
     * 3. ConverterMapper中的ignoreEmpty如果为false，但是如果存在DefaultValueMethod或者JudgeEmptyMethod
     * 方法，则仍然生效
     *
     * 4. judgeSame的前提是target和source的类型是一致或者存在TypeChangeMethod
     *
     * 5. 所有方法的类型匹配都会递归向父类索引，也就是HashMap找不到则会找Map，最后到Object
     */
    private void testBeanMethodConverter() {
        TestBeanMethodConverter.EntityA entityA = new TestBeanMethodConverter.EntityA();
        entityA.setChangeData(100);
        entityA.setNotChangeData(200);
        entityA.setAssignData(300);
        entityA.setSameData("same");
        entityA.setNotSameData("notSame");
        TestBeanMethodConverter.EntityB entityB = new TestBeanMethodConverter.EntityB();
        entityB.setSameData(1);
        entityB.setNotSameData(2);
        TestBeanMethodConverter converter = ConverterHolder.getConverter(TestBeanMethodConverter.class);
        System.out.println("testBeanMethodConverter---------------- 旧对象A：" + JSON.toJSONString(entityA));
        System.out.println("testBeanMethodConverter---------------- 旧对象B：" + JSON.toJSONString(entityB));
        MergeResult<TestBeanMethodConverter.EntityB> entityBMergeResult = converter.mergeTo(entityA, entityB);
        System.out.println("testBeanMethodConverter ---------------- 新对象B：" + JSON.toJSONString(entityBMergeResult));
        System.out.println("");
    }

    /**
     * 指定方法
     * JudgeEmptyMethod - 判断参数是否为空，返回值为boolean，匹配规则：入参类型和Source的类型
     * DefaultValueMethod - 默认值，如果参数为空，则修改为默认值，匹配规则：返回的类型和Source参数的类型
     * TypeChangeMethod - 类型转换，比如int -> String， 匹配规则：参数1的类型和Source参数类型，返回类型和target参数类型
     * postConvertToMap - ConvertToMap 之后触发, 能改变最终返回的Map<String, Object>
     * preConvertFromMap - ConvertFromMap 之前触发
     * postConvertFromMap - ConvertFromMap 之后触发， 能改变最终返回的Entity
     *
     * 参数说明:
     * fieldNameFilter - 字段过滤（name，注释，正则）指定字段生效或者不生效
     * primary - 多个规则生效的情况下，提高优先度， 默认前面的方法优先度更高（不能完全保证），所以primary最好只有一个
     *
     * 特殊规则 ：
     * 1. 由于fromMap方式入参是Object，所以要特殊处理：
     *  1）assignFromMap 为true时， 非fromMap方法不生效，
     *  2）assignFromMap 为false时（默认），assignFieldName在fromMap方法不生, 其他属性则无影响都会生效
     *  3）由于入参是Object, fromMap会先强制转换成target对应字段的类型，所以DefaultValueMethod，JudgeEmptyMethod
     * 是根据target的参数类型匹配的，而TypeChangeMethod则不受影响，还是根据参数1类型是Object，返回类型和target参数类型
     *
     * 2. ConverterMapper中的defaultValue如果为false，则DefaultValueMethod不生效
     *
     * 3. ConverterMapper中的ignoreEmpty如果为false，但是如果存在DefaultValueMethod或者JudgeEmptyMethod
     * 方法，则仍然生效
     *
     * 4. 所有方法的类型匹配都会递归向父类索引，也就是HashMap找不到则会找Map，最后到Object
     */
    private void testMapMethodConverter() {
        TestMapMethodConverter.EntityA entityA = new TestMapMethodConverter.EntityA();
        entityA.setChangeData(100);
        entityA.setNotChangeData(200);
        entityA.setAssignData(300);
        entityA.setFromMapData(1000);
        TestMapMethodConverter converter = ConverterHolder.getConverter(TestMapMethodConverter.class);
        System.out.println("testMapMethodConverter(toMap) ---------------- 旧对象A：" + JSON.toJSONString(entityA));
        Map<String, Object> dataMap = converter.convertToMap(entityA);
        System.out.println("testMapMethodConverter(toMap) ---------------- 新对象B：" + JSON.toJSONString(dataMap));
        System.out.println("testMapMethodConverter(FromMap) ---------------- 旧对象Map：" + JSON.toJSONString(dataMap));
        TestMapMethodConverter.EntityA newEntityA = converter.convertFromMap(dataMap);
        System.out.println("testMapMethodConverter(FromMap) ---------------- 新对象：" + JSON.toJSONString(newEntityA));
        System.out.println("");
    }

    /**
     * ConverterMapping 参数
     * 注释在convertFromMap，convertToMap， convertTo， mergeTo 方法上，覆盖ConverterMapper配置，要显示配置参数，默认值默认不生效
     * ignoreEmpty - 忽略空值，如果是空值则不赋值, 为true, entityB的EmptyData会保留hasData值，为false，则被替换为null
     * ignoreGenericType - 忽略泛型，Map<String, Integer> 能和 Map 匹配
     * matchType -  为true，则listData不会生成，为false，则listData会生成, 并且会报错，类型转换错误
     * reNameField - 字段名别名映射
     * fieldNameFilter - 字段过滤（name，注释，正则）指定字段生效或者不生效
     */
    private void testMappingFieldConverter() {
        TestMappingFieldConverter.EntityA entityA = new TestMappingFieldConverter.EntityA();
        entityA.setAge(1);
        entityA.setListData(Sets.newHashSet("123"));
        entityA.setOldName("123");
        entityA.setIgnoreFiled("nameA");
        HashMap<String, Integer> mapData = new HashMap<>();
        mapData.put("test", 123);
        entityA.setMapData(mapData);
        TestMappingFieldConverter converter = ConverterHolder.getConverter(TestMappingFieldConverter.class);
        TestMappingFieldConverter.EntityB entityB = new TestMappingFieldConverter.EntityB();
        entityB.setEmptyData("hasData");
        entityB.setIgnoreFiled("nameB");
        System.out.println("testMappingFieldConverter ---------------- 旧对象A：" + JSON.toJSONString(entityA));
        System.out.println("testMappingFieldConverter ---------------- 旧对象B：" + JSON.toJSONString(entityB));
        converter.mergeTo(entityA, entityB);
        System.out.println("testMappingFieldConverter ---------------- 新对象B：" + JSON.toJSONString(entityB));
        System.out.println("");
    }

    /**
     * ConverterMapper 参数
     * ignoreEmpty - 忽略空值，如果是空值则不赋值, 为true, entityB的EmptyData会保留hasData值，为false，则被替换为null
     * ignoreGenericType - 忽略泛型，Map<String, Integer> 能和 Map 匹配
     * matchType -  为true，则listData不会生成，为false，则listData会生成, 并且会报错，类型转换错误
     * reNameField - 字段名别名映射
     * fieldNameFilter - 字段过滤（name，注释，正则）指定字段生效或者不生效
     */
    private void testMapperFieldConverter() {
        TestMapperFieldConverter.EntityA entityA = new TestMapperFieldConverter.EntityA();
        entityA.setAge(1);
        entityA.setListData(Sets.newHashSet("123"));
        entityA.setOldName("123");
        entityA.setIgnoreFiled("nameA");
        HashMap<String, Integer> mapData = new HashMap<>();
        mapData.put("test", 123);
        entityA.setMapData(mapData);
        TestMapperFieldConverter converter = ConverterHolder.getConverter(TestMapperFieldConverter.class);
        TestMapperFieldConverter.EntityB entityB = new TestMapperFieldConverter.EntityB();
        entityB.setEmptyData("hasData");
        entityB.setIgnoreFiled("nameB");
        System.out.println("testMapperFieldConverter ---------------- 旧对象A：" + JSON.toJSONString(entityA));
        System.out.println("testMapperFieldConverter ---------------- 旧对象B：" + JSON.toJSONString(entityB));
        converter.mergeTo(entityA, entityB);
        System.out.println("testMapperFieldConverter ---------------- 新对象B：" + JSON.toJSONString(entityB));
        System.out.println("");
    }

    /**
     * 注入使用
     */
    private void testComponentConverter() {
        TestComponentConverter.EntityA entityA = new TestComponentConverter.EntityA();
        entityA.setAge(1);
        HashMap<String, Integer> mapData = new HashMap<>();
        mapData.put("test", 123);
        entityA.setMapData(mapData);
        Map<String, Object> entityMap = testComponentConverter.convertToMap(entityA);
        System.out.println("testComponentConverter ---------------- 旧对象：" + JSON.toJSONString(entityA));
        System.out.println("testComponentConverter ---------------- 新对象：" + JSON.toJSONString(entityMap));
        System.out.println("");
    }

    /**
     * 最简单的Bean -> Map转换
     */
    private void testBaseMapConverter() {
        TestMapConverter.EntityA entityA = new TestMapConverter.EntityA();
        entityA.setAge(1);
        HashMap<String, Integer> mapData = new HashMap<>();
        mapData.put("test", 123);
        entityA.setMapData(mapData);
        TestMapConverter converter = ConverterHolder.getConverter(TestMapConverter.class);
        Map<String, Object> entityMap = converter.convertToMap(entityA);
        System.out.println("testBaseMapConverter ---------------- 旧对象：" + JSON.toJSONString(entityA));
        System.out.println("testBaseMapConverter ---------------- 新对象：" + JSON.toJSONString(entityMap));
        System.out.println("");
    }

    /**
     * 最简单的Bean -> Bean转换
     * MergeResult : 两个对象合并的结果
     * change ： 是否有变化
     * changeFieldNames ： target有赋值的字段
     * entity ： target对象
     */
    private void testBaseBeanConverter() {
        TestBeanConverter.EntityA entityA = new TestBeanConverter.EntityA();
        entityA.setAge(1);
        HashMap<String, Integer> mapData = new HashMap<>();
        mapData.put("test", 123);
        entityA.setMapData(mapData);
        TestBeanConverter converter = ConverterHolder.getConverter(TestBeanConverter.class);
        TestBeanConverter.EntityB entityB = converter.convertTo(entityA);
        System.out.println("testBaseBeanConverter ---------------- 旧对象A：" + JSON.toJSONString(entityA));
        System.out.println("testBaseBeanConverter ---------------- 新对象：" + JSON.toJSONString(entityB));
        System.out.println("");
        MergeResult<TestBeanConverter.EntityB> entityBMergeResult = converter.mergeTo(entityA, entityB);
        System.out.println("testBaseBeanConverter ---------------- MergeResult：" + JSON.toJSONString(entityBMergeResult));
        System.out.println("");
    }

}
